/*
 * author M.Chang
 *
 * Copyright 2008 Ph.Bonnet and M.Chang
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

#include "BasisProbe.h"



size_t subtractCenter(int * utility_array, size_t left, size_t right);

/*****************************************************************************/

/* constructor */
BasisProbe::BasisProbe()
  : DataSetGenerator()
{
  std::cout << "BasisProbe created" << std::endl;
}

/* destructor */
BasisProbe::~BasisProbe()
{
  std::cout << "BasisProbe destructor called" << std::endl;
}



void BasisProbe::generateDataSet(std::map<std::string, double>& parameter_map, DataSet& es)
{

  int points = int (round(parameter_map["points"]));
  int offset = int (round(parameter_map["offset"]));
  int utility = int (round(parameter_map["utility"]));
  int energy = int (round(parameter_map["energy"]));
  int transmit = int (round(parameter_map["transmit"]));
  int bandwidth = int (round(parameter_map["bandwidth"]));
  int neighbor_time = int (round(parameter_map["neighbor_time"]));
  int neighbor_energy = int (round(parameter_map["neighbor_energy"]));
  int duration = int (round(parameter_map["duration"]));
  int frequency = int (round(parameter_map["frequency"]));

  int begin = int (round(parameter_map["begin"]));
  int end = int (round(parameter_map["end"]));


  points = (points > 0) ? points : base_points;
  utility = (utility > 0) ? utility : base_utility;
  energy = (energy > 0) ? energy : base_energy[0];
  transmit = (transmit > 0) ? transmit : base_transmit[0];
  bandwidth = (bandwidth > 0) ? bandwidth : base_bandwidth[0];
  neighbor_time = (neighbor_time > 0) ? neighbor_time : base_neighbor_time[0];
  neighbor_energy = (neighbor_energy > 0) ? neighbor_energy : base_neighbor_energy[0];
  duration = (duration > 0) ? duration : base_duration[0];
  frequency = (frequency > 0) ? frequency : base_frequency[0];
  begin = (begin > 0) ? begin : base_begin;
  end = (end > 0) ? end : base_end;




  if (points == 1)
  {
    es.addElement(base_begin + offset, utility, energy, duration, transmit, bandwidth, neighbor_energy, neighbor_time);
  }
  else
  {
    int * utility_array = new int[points];

    for (int i = 0; i < points; i++)
    {
      utility_array[i] = utility;
    }

//    size_t bonus = subtractCenter(utility_array, 0, points - 2);
//    utility_array[points-1] += bonus - 2;

    if (points == 10)
    {
      for (int i = 0; i < points; i++)
      {
        es.addElement(base_elements[i], utility_array[i], base_energy[i], base_duration[i], base_transmit[i], base_bandwidth[i], base_neighbor_energy[i], base_neighbor_time[i]);
      }

      std::set<int> frequency_set(base_frequency, base_frequency+sizeof(base_frequency)/sizeof(int));
      es.addFrequencySet(frequency_set);
    }
    else
    {
      double interval = (base_end - base_begin) / (points - 1);

      for (int i = 0; i < points; i++)
      {
        int element = int (round(base_begin + i*interval)) + offset;

        if (element > 0)
          es.addElement(element, utility, energy, duration, transmit, bandwidth, neighbor_energy, neighbor_time);
//          es.addElement(element, utility_array[i], energy, duration, transmit, bandwidth);
      }

//      std::set<int> frequency_set;
//      frequency_set.insert(frequency);
      std::set<int> frequency_set(base_frequency, base_frequency+sizeof(base_frequency)/sizeof(int));
      es.addFrequencySet(frequency_set);
    }

    delete utility_array;
  }


}


/*****************************************************************************/
size_t subtractCenter(int * utility_array, size_t left, size_t right)
{
  if (left >= right)
    return 1;

  if ( (right - left) == 1 )
  {
    utility_array[left] += 0;
    utility_array[right] += 1;

    return 2;
  }

  size_t center = left + ((right - left) / 2);


  size_t b1 = subtractCenter(utility_array, center + 1, right);
  size_t b2 = subtractCenter(utility_array, left, center - 1);
  size_t bonus = (b1 > b2) ? b1 : b2;

  utility_array[center] += bonus;

  return bonus + 1;
}

